<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>31.3. Zend_OpenId_Provider</title>
<link rel="stylesheet" href="dbstyle.css" type="text/css">
<meta name="generator" content="DocBook XSL Stylesheets V1.72.0">
<link rel="start" href="index.html" title="Programmer's Reference Guide">
<link rel="up" href="zend.openid.html" title="Chapter 31. Zend_OpenId">
<link rel="prev" href="zend.openid.consumer.html" title="31.2. Zend_OpenId_Consumer Basics">
<link rel="next" href="zend.paginator.html" title="Chapter 32. Zend_Paginator">
<link rel="chapter" href="introduction.html" title="Chapter 1. Introduction to Zend Framework">
<link rel="chapter" href="zend.acl.html" title="Chapter 2. Zend_Acl">
<link rel="chapter" href="zend.auth.html" title="Chapter 3. Zend_Auth">
<link rel="chapter" href="zend.cache.html" title="Chapter 4. Zend_Cache">
<link rel="chapter" href="zend.config.html" title="Chapter 5. Zend_Config">
<link rel="chapter" href="zend.console.getopt.html" title="Chapter 6. Zend_Console_Getopt">
<link rel="chapter" href="zend.controller.html" title="Chapter 7. Zend_Controller">
<link rel="chapter" href="zend.currency.html" title="Chapter 8. Zend_Currency">
<link rel="chapter" href="zend.date.html" title="Chapter 9. Zend_Date">
<link rel="chapter" href="zend.db.html" title="Chapter 10. Zend_Db">
<link rel="chapter" href="zend.debug.html" title="Chapter 11. Zend_Debug">
<link rel="chapter" href="zend.dojo.html" title="Chapter 12. Zend_Dojo">
<link rel="chapter" href="zend.dom.html" title="Chapter 13. Zend_Dom">
<link rel="chapter" href="zend.exception.html" title="Chapter 14. Zend_Exception">
<link rel="chapter" href="zend.feed.html" title="Chapter 15. Zend_Feed">
<link rel="chapter" href="zend.filter.html" title="Chapter 16. Zend_Filter">
<link rel="chapter" href="zend.form.html" title="Chapter 17. Zend_Form">
<link rel="chapter" href="zend.gdata.html" title="Chapter 18. Zend_Gdata">
<link rel="chapter" href="zend.http.html" title="Chapter 19. Zend_Http">
<link rel="chapter" href="zend.infocard.html" title="Chapter 20. Zend_InfoCard">
<link rel="chapter" href="zend.json.html" title="Chapter 21. Zend_Json">
<link rel="chapter" href="zend.layout.html" title="Chapter 22. Zend_Layout">
<link rel="chapter" href="zend.ldap.html" title="Chapter 23. Zend_Ldap">
<link rel="chapter" href="zend.loader.html" title="Chapter 24. Zend_Loader">
<link rel="chapter" href="zend.locale.html" title="Chapter 25. Zend_Locale">
<link rel="chapter" href="zend.log.html" title="Chapter 26. Zend_Log">
<link rel="chapter" href="zend.mail.html" title="Chapter 27. Zend_Mail">
<link rel="chapter" href="zend.measure.html" title="Chapter 28. Zend_Measure">
<link rel="chapter" href="zend.memory.html" title="Chapter 29. Zend_Memory">
<link rel="chapter" href="zend.mime.html" title="Chapter 30. Zend_Mime">
<link rel="chapter" href="zend.openid.html" title="Chapter 31. Zend_OpenId">
<link rel="chapter" href="zend.paginator.html" title="Chapter 32. Zend_Paginator">
<link rel="chapter" href="zend.pdf.html" title="Chapter 33. Zend_Pdf">
<link rel="chapter" href="zend.registry.html" title="Chapter 34. Zend_Registry">
<link rel="chapter" href="zend.rest.html" title="Chapter 35. Zend_Rest">
<link rel="chapter" href="zend.search.lucene.html" title="Chapter 36. Zend_Search_Lucene">
<link rel="chapter" href="zend.server.html" title="Chapter 37. Zend_Server">
<link rel="chapter" href="zend.service.html" title="Chapter 38. Zend_Service">
<link rel="chapter" href="zend.session.html" title="Chapter 39. Zend_Session">
<link rel="chapter" href="zend.soap.html" title="Chapter 40. Zend_Soap">
<link rel="chapter" href="zend.test.html" title="Chapter 41. Zend_Test">
<link rel="chapter" href="zend.text.html" title="Chapter 42. Zend_Text">
<link rel="chapter" href="zend.timesync.html" title="Chapter 43. Zend_TimeSync">
<link rel="chapter" href="zend.translate.html" title="Chapter 44. Zend_Translate">
<link rel="chapter" href="zend.uri.html" title="Chapter 45. Zend_Uri">
<link rel="chapter" href="zend.validate.html" title="Chapter 46. Zend_Validate">
<link rel="chapter" href="zend.version.html" title="Chapter 47. Zend_Version">
<link rel="chapter" href="zend.view.html" title="Chapter 48. Zend_View">
<link rel="chapter" href="zend.xmlrpc.html" title="Chapter 49. Zend_XmlRpc">
<link rel="appendix" href="requirements.html" title="Appendix A. Zend Framework Requirements">
<link rel="appendix" href="coding-standard.html" title="Appendix B. Zend Framework Coding Standard for PHP">
<link rel="appendix" href="copyrights.html" title="Appendix C. Copyright Information">
<link rel="index" href="the.index.html" title="Index">
<link rel="subsection" href="zend.openid.provider.html#zend.openid.provider.start" title="31.3.1. Quick Start">
<link rel="subsection" href="zend.openid.provider.html#zend.openid.provider.all" title="31.3.2. Combine all together">
<link rel="subsection" href="zend.openid.provider.html#zend.openid.provider.sreg" title="31.3.3. Simple Registration Extension">
<link rel="subsection" href="zend.openid.provider.html#zend.openid.provider.else" title="31.3.4. What Else?">
</head>
<body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF">
<div class="navheader"><table width="100%" summary="Navigation header">
<tr><th colspan="3" align="center">31.3. Zend_OpenId_Provider</th></tr>
<tr>
<td width="20%" align="left">
<a accesskey="p" href="zend.openid.consumer.html">Prev</a> </td>
<th width="60%" align="center">Chapter 31. Zend_OpenId</th>
<td width="20%" align="right"> <a accesskey="n" href="zend.paginator.html">Next</a>
</td>
</tr>
</table></div>
<div class="sect1" lang="en">
<div class="titlepage"><div><div><h2 class="title" style="clear: both">
<a name="zend.openid.provider"></a>31.3. Zend_OpenId_Provider</h2></div></div></div>
<p>
        The <code class="code">Zend_OpenId_Provider</code> is used to implement OpenID
        servers. This chapter provides very basic examples demonstrating how to
        build a working server. However, for implementation of a production OpenID
        server (like <a href="http://www.myopenid.com" target="_top">www.myopenid.com</a>) you
        may be required to deal with more complex issues.
    </p>
<div class="sect2" lang="en">
<div class="titlepage"><div><div><h3 class="title">
<a name="zend.openid.provider.start"></a>31.3.1. Quick Start</h3></div></div></div>
<p>
            The following identity includes the code for creating a user account
            using <code class="code">Zend_OpenId_Provider::register</code>. The link element with
            <code class="code">rel="openid.server"</code> points to our own server script. If you
            submit this identity to an OpenID-enabled site, it will perform
            authentication on this server.
        </p>
<p>
            The code before &lt;html&gt; is just a trick that automatically
            creates a user account. You wont need such code when using real
            identities.
        </p>
<div class="example">
<a name="zend.openid.provider.example-1"></a><p class="title"><b>Example 31.11. The Identity</b></p>
<div class="example-contents"><pre class="programlisting">&lt;?php
require_once "Zend/OpenId/Provider.php";
define("TEST_SERVER", Zend_OpenId::absoluteURL("example-8.php"));
define("TEST_ID", Zend_OpenId::selfURL());
define("TEST_PASSWORD", "123");
$server = new Zend_OpenId_Provider();
if (!$server-&gt;hasUser(TEST_ID)) {
    $server-&gt;register(TEST_ID, TEST_PASSWORD);
}
?&gt;
&lt;html&gt;&lt;head&gt;
&lt;link rel="openid.server" href="&lt;?php echo TEST_SERVER;?&gt;" /&gt;
&lt;/head&gt;&lt;body&gt;
&lt;?php echo TEST_ID;?&gt;
&lt;/body&gt;&lt;/html&gt;
            </pre></div>
</div>
<br class="example-break"><p>
            The following identity server script handles two kinds of requests
            from OpenID-enabled sites (for association and authentication). Both of
            them are handled by the same method
            <code class="code">Zend_OpenId_Provider::handle</code>. The two arguments to
            <code class="code">Zend_OpenId_Provider</code> are URLs of login and trust pages, these
            ask for interaction from the end-user.
        </p>
<p>
            On success, the method <code class="code">Zend_OpenId_Provider::handle</code>
            returns a string that should be passed back to the OpenID-enabled site. On
            failure, it returns <code class="code">false</code> - in this example it will return a
            HTTP 403 response. You will get it if you try to open this page by
            web-browser, because it sends a non-OpenID conformed request.
        </p>
<div class="example">
<a name="zend.openid.provider.example-2"></a><p class="title"><b>Example 31.12. Simple Identity Provider</b></p>
<div class="example-contents"><pre class="programlisting">&lt;?php
require_once "Zend/OpenId/Provider.php";
$server = new Zend_OpenId_Provider("example-8-login.php", "example-8-trust.php");
$ret = $server-&gt;handle();
if (is_string($ret)) {
    echo $ret;
} else if ($ret !== true) {
    header('HTTP/1.0 403 Forbidden');
    echo 'Forbidden';
}
            </pre></div>
</div>
<br class="example-break"><p>
            It is a good idea to use a secure connection (HTTPS) for this and
            especially for the following interactive scripts, to prevent password
            disclosure.
        </p>
<p>
            The following script implements a login screen for an identity
            server <code class="code">Zend_OpenId_Provider</code> and redirects to this page when a
            required user has not yet logged-in. On this page, users enter a password
            to login.
        </p>
<p>
            You should use the password "123" that was used during a tricky user
            registration from an identity script.
        </p>
<p>
            On submit, the script calls <code class="code">Zend_OpenId_Provider::login</code>
            with the accepted end-user's identity and password, then redirects it back
            to the main identity provider's script. On success, the
            <code class="code">Zend_OpenId_Provider::login</code> establishes a session between the
            end-user and the identity-provider and stores the information about
            logged-in user. So, all following requests from the same end-user won't
            require login procedure (even if they come from another OpenID enabled
            web-site).
        </p>
<p>
            Note that this session is between end-user and identity provider
            only. OpenID enabled sites know nothing about it.
        </p>
<div class="example">
<a name="zend.openid.provider.example-3"></a><p class="title"><b>Example 31.13. Simple Login Screen</b></p>
<div class="example-contents"><pre class="programlisting">&lt;?php
require_once "Zend/OpenId/Provider.php";
$server = new Zend_OpenId_Provider();

if ($_SERVER['REQUEST_METHOD'] == 'POST' &amp;&amp;
    isset($_POST['openid_action']) &amp;&amp;
    $_POST['openid_action'] === 'login' &amp;&amp;
    isset($_POST['openid_identifier']) &amp;&amp;
    isset($_POST['openid_password'])) {
    $server-&gt;login($_POST['openid_identifier'], $_POST['openid_password']);
    Zend_OpenId::redirect("example-8.php", $_GET);
}
?&gt;
&lt;html&gt;&lt;body&gt;
&lt;form method="post"&gt;&lt;fieldset&gt;
&lt;legend&gt;OpenID Login&lt;/legend&gt;
&lt;table border=0&gt;
&lt;tr&gt;&lt;td&gt;Name:&lt;/td&gt;&lt;td&gt;&lt;input type="text" name="openid_identifier" value="&lt;?php
echo htmlspecialchars($_GET['openid_identity']);
?&gt;"&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Password:&lt;/td&gt;&lt;td&gt;&lt;input type="text" name="openid_password" value=""&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&amp;nbsp;&lt;/td&gt;&lt;td&gt;&lt;input type="submit" name="openid_action" value="login"&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;&lt;/fieldset&gt;&lt;/form&gt;&lt;/body&gt;&lt;/html&gt;
            </pre></div>
</div>
<br class="example-break"><p>
            The fact that the user is logged-in doesn't mean that the
            authentication must succeed. The user may decide to trust or not to trust
            particular OpenID enabled sites. The following trust screen allows the
            end-user to make that choise. This choise may be done only for current
            requests or "forever". In the last case information about
            trusted/untrusted sites is stored in an internal database and all
            following authentication requests from this site will be handled
            automatically, without user interaction.
        </p>
<div class="example">
<a name="zend.openid.provider.example-4"></a><p class="title"><b>Example 31.14. Simple Trust Screen</b></p>
<div class="example-contents"><pre class="programlisting">&lt;?php
require_once "Zend/OpenId/Provider.php";
$server = new Zend_OpenId_Provider();

if ($_SERVER['REQUEST_METHOD'] == 'POST' &amp;&amp;
    isset($_POST['openid_action']) &amp;&amp;
    $_POST['openid_action'] === 'trust') {

    if (isset($_POST['allow'])) {
        if (isset($_POST['forever'])) {
            $server-&gt;allowSite($server-&gt;getSiteRoot($_GET));
        }
        $server-&gt;respondToConsumer($_GET);
    } else if (isset($_POST['deny'])) {
        if (isset($_POST['forever'])) {
            $server-&gt;denySite($server-&gt;getSiteRoot($_GET));
        }
        Zend_OpenId::redirect($_GET['openid_return_to'], array('openid.mode'=&gt;'cancel'));
    }
}
?&gt;
&lt;html&gt;&lt;body&gt;
&lt;p&gt;A site identifying as &lt;a href="&lt;?php echo htmlspecialchars($server-&gt;getSiteRoot($_GET));?&gt;"&gt;
&lt;?php echo htmlspecialchars($server-&gt;getSiteRoot($_GET));?&gt;&lt;/a&gt; has asked us for confirmation that
&lt;a href="&lt;?php echo htmlspecialchars($server-&gt;getLoggedInUser());?&gt;"&gt;
&lt;?php echo htmlspecialchars($server-&gt;getLoggedInUser());?&gt;&lt;/a&gt; is your identity URL.&lt;/p&gt;
&lt;form method="post"&gt;
&lt;input type="checkbox" name="forever"&gt;
&lt;label for="forever"&gt;forever&lt;/label&gt;&lt;br&gt;
&lt;input type="hidden" name="openid_action" value="trust"&gt;
&lt;input type="submit" name="allow" value="Allow"&gt;
&lt;input type="submit" name="deny" value="Deny"&gt;
&lt;/form&gt;&lt;/body&gt;&lt;/html&gt;
            </pre></div>
</div>
<br class="example-break"><p>
            Production OpenID servers usually support Simple Registration
            Extension that allows consumers to ask some information about user from
            provider. In this case the trust page is usually extended with ability to
            enter requested fields or to select user profile.
        </p>
</div>
<div class="sect2" lang="en">
<div class="titlepage"><div><div><h3 class="title">
<a name="zend.openid.provider.all"></a>31.3.2. Combine all together</h3></div></div></div>
<p>
            It is possible to combine all provider functions in one script. In
            this case login and trust URLs are omitted, and
            <code class="code">Zend_OpenId_Provider</code> assumes that they point to the same page
            with additional "openid.action" GET argument.
        </p>
<p>
            The following example is not complete. It doesn't provide GUI for
            end-user like it should, but performs automatic login and trusting instead.
            It is done just to simplify the example, and real server must include code
            from previous examples.
        </p>
<div class="example">
<a name="zend.openid.provider.example-5"></a><p class="title"><b>Example 31.15. All together</b></p>
<div class="example-contents"><pre class="programlisting">&lt;?php
require_once "Zend/OpenId/Provider.php";
$server = new Zend_OpenId_Provider();

define("TEST_ID", Zend_OpenId::absoluteURL("example-9-id.php"));
define("TEST_PASSWORD", "123");

if ($_SERVER['REQUEST_METHOD'] == 'GET' &amp;&amp;
    isset($_GET['openid_action']) &amp;&amp;
    $_GET['openid_action'] === 'login') {
    $server-&gt;login(TEST_ID, TEST_PASSWORD);
    unset($_GET['openid_action']);
    Zend_OpenId::redirect(Zend_OpenId::selfUrl(), $_GET);
} else if ($_SERVER['REQUEST_METHOD'] == 'GET' &amp;&amp;
    isset($_GET['openid_action']) &amp;&amp;
    $_GET['openid_action'] === 'trust') {
    unset($_GET['openid_action']);
    $server-&gt;respondToConsumer($_GET);
} else {
    $ret = $server-&gt;handle();
    if (is_string($ret)) {
        echo $ret;
    } else if ($ret !== true) {
        header('HTTP/1.0 403 Forbidden');
        echo 'Forbidden';
    }
}
            </pre></div>
</div>
<br class="example-break"><p>
            If you compare this example with previous example divided to
            separate page, in addition to dispatch code you will see only the one
            difference - <code class="code">unset($_GET['openid_action'])</code>. This
            <code class="code">unset</code> is necessary to route next request to main
            handler.
        </p>
</div>
<div class="sect2" lang="en">
<div class="titlepage"><div><div><h3 class="title">
<a name="zend.openid.provider.sreg"></a>31.3.3. Simple Registration Extension</h3></div></div></div>
<p>
            The following identity page makes a trick again. It creates new user
            account and associates it with profile (nickname and password). Such
            tricks aren't needed in real life where end-user registers on OpenID
            server and fill-in their profiles, but implementing this GUI is not a
            subject of this manual.
        </p>
<div class="example">
<a name="zend.openid.provider.example-6"></a><p class="title"><b>Example 31.16. Identity with Profile</b></p>
<div class="example-contents"><pre class="programlisting">&lt;?php
require_once "Zend/OpenId/Provider.php";
require_once "Zend/OpenId/Extension/Sreg.php";
define("TEST_SERVER", Zend_OpenId::absoluteURL("example-10.php"));
define("TEST_ID", Zend_OpenId::selfURL());
define("TEST_PASSWORD", "123");
$server = new Zend_OpenId_Provider();
if (!$server-&gt;hasUser(TEST_ID)) {
    $server-&gt;register(TEST_ID, TEST_PASSWORD);
    $server-&gt;login(TEST_ID, TEST_PASSWORD);
    $sreg = new Zend_OpenId_Extension_Sreg(array(
        'nickname' =&gt;'test',
        'email' =&gt; 'test@test.com'
    ));
    $root = Zend_OpenId::absoluteURL(".");
    Zend_OpenId::normalizeUrl($root);
    $server-&gt;allowSite($root, $sreg);
    $server-&gt;logout();
}
?&gt;
&lt;html&gt;&lt;head&gt;
&lt;link rel="openid.server" href="&lt;?php echo TEST_SERVER;?&gt;" /&gt;
&lt;/head&gt;&lt;body&gt;
&lt;?php echo TEST_ID;?&gt;
&lt;/body&gt;&lt;/html&gt;
            </pre></div>
</div>
<br class="example-break"><p>
            You should pass this identity to OpenID-enabled site (use Simple
            Registration Extension example from previous chapter) and it will use the
            following OpenID server script.
        </p>
<p>
            It is a variation from previous "All together" example. It uses the
            same automatic login mechanism, but it doesn't contain any code for trust
            page. The user already trusts "forever" to example scripts. This trust was
            made by <code class="code">Zend_OpenId_Provider::alowSite</code> method in identity
            script. The same method associated profile with trusted URL and this
            profile will be returned automatically on request from this trusted
            URL.
        </p>
<p>
            The only thing necessary to make Simple Registration Extension work
            is passing object of <code class="code">Zend_OpenId_Extension_Sreg</code> as second
            argument to <code class="code">Zend_OpenId_Provider::handle</code>.
        </p>
<div class="example">
<a name="zend.openid.provider.example-7"></a><p class="title"><b>Example 31.17. Provider with SREG</b></p>
<div class="example-contents"><pre class="programlisting">&lt;?php
require_once "Zend/OpenId/Provider.php";
require_once "Zend/OpenId/Extension/Sreg.php";
$server = new Zend_OpenId_Provider();
$sreg = new Zend_OpenId_Extension_Sreg();

define("TEST_ID", Zend_OpenId::absoluteURL("example-10-id.php"));
define("TEST_PASSWORD", "123");

if ($_SERVER['REQUEST_METHOD'] == 'GET' &amp;&amp;
    isset($_GET['openid_action']) &amp;&amp;
    $_GET['openid_action'] === 'login') {
    $server-&gt;login(TEST_ID, TEST_PASSWORD);
    unset($_GET['openid_action']);
    Zend_OpenId::redirect(Zend_OpenId::selfUrl(), $_GET);
} else if ($_SERVER['REQUEST_METHOD'] == 'GET' &amp;&amp;
    isset($_GET['openid_action']) &amp;&amp;
    $_GET['openid_action'] === 'trust') {
   echo "UNTRUSTED DATA" ;
} else {
    $ret = $server-&gt;handle(null, $sreg);
    if (is_string($ret)) {
        echo $ret;
    } else if ($ret !== true) {
        header('HTTP/1.0 403 Forbidden');
        echo 'Forbidden';
    }
}
            </pre></div>
</div>
<br class="example-break">
</div>
<div class="sect2" lang="en">
<div class="titlepage"><div><div><h3 class="title">
<a name="zend.openid.provider.else"></a>31.3.4. What Else?</h3></div></div></div>
<p>
            Building OpenID servers is less usual tasks then building
            OpenID-enabled sites, so this manual don't try to cover all
            <code class="code">Zend_OpenId_Provider</code> features as it was done for
            <code class="code">Zend_OpenId_Consumer</code>.
        </p>
<p>
            In two words in additional it provides:
        </p>
<div class="itemizedlist"><ul type="disc">
<li><p>
                    a set of methods to build end-user's GUI interface that allows
                    users to register, manage their trusted sites and profiles.
                </p></li>
<li><p>
                    an abstraction storage layer to store information about users,
                    their sites and profiles. It also stores associations between
                    provider and OpenID-enabled sites. This layer is very similar
                    to the <code class="code">Zend_OpenId_Consumer</code>'s one. It also uses
                    file storage by default but may be substituted with another
                    implementation.
                </p></li>
<li><p>
                    an abstraction user-association layer that may associate
                    end-user's web browser with logged-in identity
                </p></li>
</ul></div>
<p>
            <code class="code">Zend_OpenId_Provider</code> doesn't try to cover all possible
            features that can be implemented by OpenID server (like digital
            certificates), but it can be easily extended using
            <code class="code">Zend_OpenId_Extension</code>s or by creating a child class.
        </p>
</div>
</div>
<div class="navfooter"><table width="100%" summary="Navigation footer">
<tr>
<td width="40%" align="left">
<a accesskey="p" href="zend.openid.consumer.html">Prev</a> </td>
<td width="20%" align="center"><a accesskey="u" href="zend.openid.html">Up</a></td>
<td width="40%" align="right"> <a accesskey="n" href="zend.paginator.html">Next</a>
</td>
</tr>
<tr>
<td width="40%" align="left" valign="top">31.2. Zend_OpenId_Consumer Basics </td>
<td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td>
<td width="40%" align="right" valign="top"> Chapter 32. Zend_Paginator</td>
</tr>
</table></div>
<div class="revinfo"></div>
</body>
</html>
